package com.touchwp.java.wechat.app;

import java.io.Writer;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.touchwp.java.common.base.Default;
import com.touchwp.java.common.exception.SystemException;
import com.touchwp.java.common.lang.Lang;
import com.touchwp.java.common.log.Log;
import com.touchwp.java.common.util.HttpKit;
import com.touchwp.java.wechat.converter.IMessageConverter;
import com.touchwp.java.wechat.message.Message;
import com.touchwp.java.wechat.processor.IMessageProcessor;

/**
 * 微信消息处理
 * 
 * @author yuki
 * 
 */
@Named
public class WeChatProcessor {

	private static Map<Class<? extends Message>, IMessageProcessor<Message>> processorMapping = null;

	@Inject
	private MessageFactory messageFactory;

	@Inject
	private List<IMessageProcessor<Message>> processors;

	@Inject
	private IMessageConverter converter;

	public WeChatProcessor() {
	}

	/**
	 * 对应消息和其处理器
	 */
	@PostConstruct
	public void init() {
		if (null != processorMapping) {
			return;
		}

		if (null == processors || processors.size() < 1) {
			Log.error("message processor required! ");
			return;
		}
		processorMapping = new HashMap<Class<? extends Message>, IMessageProcessor<Message>>(processors.size());
		for (IMessageProcessor<Message> messageProcessor : processors) {
			Class<Message> key = getMessageClass(messageProcessor);
			if (processorMapping.containsKey(key)) {
				if (messageProcessor.getClass().isAnnotationPresent(Default.class)) {
					continue;
				} else if (!processorMapping.get(key).getClass().isAnnotationPresent(Default.class)) {
					throw new SystemException(key.getSimpleName() + "多个处理器");
				}
			}
			processorMapping.put(key, messageProcessor);
		}
	}

	/**
	 * 处理消息入口
	 * 
	 * @param request
	 * @param response
	 */
	public void process(HttpServletRequest request, HttpServletResponse response) {
		check(request, response);
		Message message = getMessage(request);
		IMessageProcessor<Message> processor = processorMapping.get(message.getClass());
		Lang.require(processor, "不支持的消息,请增加处理器");
		Message result = processor.process(message);
		sendMessage(result, response);
	}

	private void check(HttpServletRequest request, HttpServletResponse response) {
		Lang.require(request, "are you kiding?");
		Lang.require(response, "are you kiding?");
	}

	/**
	 * 发送消息
	 * 
	 * @param message
	 * @param response
	 */
	private void sendMessage(Message message, HttpServletResponse response) {
		Writer writer = null;
		try {
			writer = response.getWriter();
			writer.append(converter.marshal(message));
		} catch (Exception e) {
			Log.error("无法响应结果!");
		}
	}

	/**
	 * 获取服务器请求内容
	 * 
	 * @param request
	 * @return
	 */
	private Message getMessage(HttpServletRequest request) {
		String content = HttpKit.getContent(request, null);
		Message message = messageFactory.getMessage(content);
		return message;
	}

	@Deprecated
	@SuppressWarnings({ "unchecked", "unused" })
	private Class<Message> getMessageClassWithParentInterface(IMessageProcessor<Message> messageProcessor) {
		Class<?>[] processInterfaces = messageProcessor.getClass().getInterfaces();
		Class<Message> result = null;
		for (Class<?> interfaceClass : processInterfaces) {
			if (IMessageProcessor.class.isAssignableFrom(interfaceClass)) {
				Type type = interfaceClass.getGenericInterfaces()[0];
				if (type instanceof ParameterizedType) {
					result = (Class<Message>) ((ParameterizedType) type).getActualTypeArguments()[0];
					break;
				}
			}
		}
		Lang.require(result, "处理器实现错误,无法获取目标类型" + messageProcessor);
		return result;
	}

	/**
	 * 获取消息类型
	 * 
	 * @param messageProcessor
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private Class<Message> getMessageClass(IMessageProcessor<Message> messageProcessor) {
		Class<Message> result = null;
		Type[] types = messageProcessor.getClass().getGenericInterfaces();
		for (Type type : types) {
			if (ParameterizedType.class.isAssignableFrom(type.getClass())) {
				ParameterizedType parameterizedType = (ParameterizedType) type;
				if (IMessageProcessor.class.isAssignableFrom((Class<?>) parameterizedType.getRawType())) {
					Type target = ((ParameterizedType) type).getActualTypeArguments()[0];
					result = (Class<Message>) target;
					break;
				}
			}
		}
		Lang.require(result, "处理器实现错误,无法获取目标类型" + messageProcessor);
		return result;
	}

	/**
	 * 手动增加处理器
	 * 
	 * @param processor
	 */
	@Deprecated
	public void addProcessor(IMessageProcessor<? extends Message> processor) {
		if (null == processors) {
			processors = new ArrayList<IMessageProcessor<Message>>();
		}
		@SuppressWarnings("unchecked")
		IMessageProcessor<Message> target = (IMessageProcessor<Message>) processor;
		this.processors.add(target);
	}
}
